#include "WinUtility.h"
#include "cacheiconprovider.h"
#include <QUrl>
#include <QDebug>
#include <shlobj_core.h>
#include <QElapsedTimer>
CacheIconProvider::CacheIconProvider()
{
}

CacheIconProvider& CacheIconProvider::instance()
{
    static CacheIconProvider instance; // singleton
    return instance;
}

QIcon CacheIconProvider::getUrlIcon(const QString& path)
{
    QIcon icon;
    static const QIcon WebIcon = QIcon(":/images/web.png");
    if (!path.isEmpty()) {
        QString scheme = QUrl(path).scheme();
        if (scheme.startsWith("http")) //特殊处理网址
            icon = WebIcon;
        else if (path.startsWith(Win::APPS_FOLDER)) { //特殊处理 shell:AppsFolder
            auto id = path.mid(QString(Win::APPS_FOLDER).length());
            if (id[1] == ':' && id[2] == '\\') // Normal
                icon = QFileIconProvider::icon(QFileInfo(path));
            else if (id[0] == '{') { // GUID
                auto r = id.indexOf('}');
                auto GUID = id.left(r + 1);
                auto path = id.replace(GUID, Win::GUID2Path(GUID));
                icon = QFileIconProvider::icon(QFileInfo(path));
            } else if (id.startsWith("Microsoft.AutoGenerated.{")) { // AutoGenerated
                icon = QFileIconProvider::icon(QFileInfo(path));
            } else { // UWP
                auto uwpDir = Win::getUWPInstallDirByAUMID(id);
                QString logoPath = uwpDir + '\\' + Win::getLogoPathFromAppxManifest(uwpDir + "\\AppxManifest.xml");
                icon = Win::loadUWPLogo(logoPath);
            }
        } else if (path.endsWith(".url")) {
            auto [url, iconPath] = Win::parseInternetShortcut(path);
            if (iconPath.isEmpty())
                icon = WebIcon;
            else {
                if (iconPath.endsWith(".exe"))
                    icon = QFileIconProvider::icon(QFileInfo(iconPath));
                else
                    icon = QIcon(iconPath);
            }
        } else
            icon = QFileIconProvider::icon(QFileInfo(path));
    }
    return icon;
}

// cache QIcon
QIcon CacheIconProvider::addCache(const QString& path)
{
    if (auto icon = iconCache.value(path); !icon.isNull())
        return icon;

    auto icon = getUrlIcon(path);
    iconCache[path] = icon;
    return icon;
}

// cache QIcon & load QPixmap forcely
// only in main thread!
void CacheIconProvider::cachePixmap(const QString& path, const QSize& size)
{
    auto icon = addCache(path);
    icon.pixmap(size); //强制缓存 （图标在这一步才真正读取），QPixmapCache必须在主线程运行，否则容易卡死
}

QIcon CacheIconProvider::icon(const QString& path) //优先从缓存中读取
{
    QElapsedTimer t;
    t.start();
    QIcon icon = iconCache.value(path);
    if (icon.isNull() && path != "") {
        iconCache[path] = icon = getUrlIcon(path);
        qDebug() << "Not Hit IconCache:" << path;
    }
    auto ms = t.elapsed();
    if (ms >= 2)
        qWarning() << "Icon load too slow:" << ms << "ms" << path;
    return icon;
}
